﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using CGShaderIntegration;


namespace CGShaderIntegration.DrawableGameComponents
{

    public class KuebrichAndiShader : Microsoft.Xna.Framework.DrawableGameComponent, IMatrices
    {
        private ContentManager content;
        private SpriteBatch spriteBatch;

        private Model erde, sonne, mond;

        public Matrix WorldMatrix { get; set; }
        public Matrix ViewMatrix { get; set; }
        public Matrix ProjectionMatrix { get; set; }

        private Effect eSchachbrett;
        private Effect eDepthMap;


        private Vector3 position_e = new Vector3(5.0f, 0.0f, 0.0f);
        private Vector3 position_s = new Vector3(0.0f, 0.0f, 0.0f);
        private Vector3 position_m = new Vector3(0.5f, 0.0f, 0.0f);

        float rotation_e = 0.0f;
        float rotation_m = 0.0f;

        private MouseState mouseState;
        private KeyboardState kbState;
        private KeyboardState kbStateOld;

        private Vector3 kameraPos = new Vector3(0.0f, 20.0f, 1.0f);

        private Vector3 moveLinZiel = new Vector3(3.0f, 0.0f, 0.0f);
        private Vector3 moveLin = new Vector3(0.0f, 0.0f, 0.0f);
        float n = 0.0f;
        int invert2 = 1;

        float keyRotateY, keyRotateX;

        int invert = 1;

        private Vector3 casteljau1 = new Vector3(1.0f, 1.0f, 0.0f);
        private Vector3 casteljau2 = new Vector3(2.0f, 5.0f, 0.0f);
        private Vector3 casteljau3 = new Vector3(3.0f, 1.0f, 0.0f);
        private Vector3 b11, b21, b31, b22, b32;

        private Vector3[] polygon;
        private Vector3[] bezier = new Vector3[] { };

        public KuebrichAndiShader(Game game)
            : base(game)
        {
            game.Components.Add(this);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            //WorldMatrix = Matrix.Identity;
            //ViewMatrix = Matrix.CreateLookAt(kameraPos, new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
            //ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio, 1.0f, 1000.0f);

            moveLin = moveLinZiel - position_s;
            polygon = new Vector3[] { position_s, casteljau1, casteljau2, casteljau3 };

            this.content = this.Game.Content;

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.

            //graphics.PreferredBackBufferWidth = 1024;
            //graphics.PreferredBackBufferHeight = 768;
            //graphics.ToggleFullScreen();
            //graphics.ApplyChanges();


            spriteBatch = new SpriteBatch(GraphicsDevice);
            erde = content.Load<Model>("models//KuebrichAndisun");
            sonne = content.Load<Model>("models//KuebrichAndisun");
            mond = content.Load<Model>("models//KuebrichAndisun");

            eSchachbrett = content.Load<Effect>("effects//KuebrichAndiSchachbrett");
            eDepthMap = content.Load<Effect>("effects//KuebrichAndidepthMap");

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Allows the game to exit

            if (n > 1 || n < 0) invert2 *= -1;
            n += 0.01f * invert2;


            /*
            /////////////Casteljau////////////
            b11 = position_s + (casteljau1 - position_s) * n;
            b21 = casteljau1 + (casteljau2 - casteljau1) * n;
            b31 = casteljau2 + (casteljau3 - casteljau2) * n;
            b22 = b11 + (b21 - b11) * n;
            b32 = b21 + (b31 - b21) * n;
            /////////////////////////////////
             * */

            mouseState = Mouse.GetState();
            kbState = Keyboard.GetState();


            // TODO: Add your update logic here
            rotation_e += 0.01f * invert;
            rotation_m += 0.12f * invert;

            if (mouseState.LeftButton == ButtonState.Pressed)
                kameraPos.Y += 0.5f;

            if (mouseState.RightButton == ButtonState.Pressed)
                kameraPos.Y -= 0.5f;

            if (kbState.IsKeyDown(Keys.Left))
                keyRotateY -= 0.01f;

            if (kbState.IsKeyDown(Keys.Right))
                keyRotateY += 0.01f;

            if (kbState.IsKeyDown(Keys.Up))
                keyRotateX -= 0.01f;

            if (kbState.IsKeyDown(Keys.Down))
                keyRotateX += 0.01f;

            if (kbState.IsKeyDown(Keys.I) && kbStateOld.IsKeyUp(Keys.I))
                invert *= -1;


            //ViewMatrix = Matrix.CreateRotationY(keyRotateY) * Matrix.CreateRotationX(keyRotateX) * Matrix.CreateLookAt(kameraPos, new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);

            kbStateOld = Keyboard.GetState();

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (ModelMesh mesh in erde.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = eDepthMap;

                    eDepthMap.Parameters["World"].SetValue(WorldMatrix * Matrix.CreateScale(0.2f, 0.2f, 0.2f) * Matrix.CreateTranslation(position_e) * Matrix.CreateRotationY(rotation_e) * mesh.ParentBone.Transform);
                    eDepthMap.Parameters["View"].SetValue(ViewMatrix);
                    eDepthMap.Parameters["fFarClipPlane"].SetValue(20.0f);
                    eDepthMap.Parameters["fNearClipPlane"].SetValue(1.0f);
                    eDepthMap.Parameters["matViewProjection"].SetValue(ProjectionMatrix);
                }
                mesh.Draw();
            }


            foreach (ModelMesh mesh in sonne.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = eSchachbrett;

                    eSchachbrett.Parameters["World"].SetValue(WorldMatrix * mesh.ParentBone.Transform);
                    //eSchachbrett.Parameters["World"].SetValue(worldMatrix * Matrix.CreateTranslation(b22 + (b32 - b22) * n) * mesh.ParentBone.Transform);
                    eSchachbrett.Parameters["View"].SetValue(ViewMatrix);
                    eSchachbrett.Parameters["chessSize"].SetValue(0.11f);
                    eSchachbrett.Parameters["matViewProjection"].SetValue(ProjectionMatrix);
                }
                mesh.Draw();
            }

            foreach (ModelMesh mesh in mond.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = eSchachbrett;

                    eSchachbrett.Parameters["World"].SetValue(WorldMatrix * Matrix.CreateScale(0.05f, 0.05f, 0.05f) * Matrix.CreateTranslation(position_m) * Matrix.CreateRotationY(rotation_m) * Matrix.CreateTranslation(position_e) * Matrix.CreateRotationY(rotation_e) * mesh.ParentBone.Transform);
                    eSchachbrett.Parameters["View"].SetValue(ViewMatrix);
                    eSchachbrett.Parameters["chessSize"].SetValue(0.11f);
                    eSchachbrett.Parameters["matViewProjection"].SetValue(ProjectionMatrix);
                }
                mesh.Draw();
            }

            base.Draw(gameTime);
        }

        public String GetName()
        {
            return ("KübrichAndi");
        }
    }
}
